<?php

namespace CZTools\Hyperf\Library;

/**
 * QP DIRTY lib class.
 */
class DirtyFilter
{
    private static DirtyFilter $instance;
    /**
     * @access  private
     * @var     resource    File name.
     */
    var $file_name = "";

    /**
     * @access  private
     * @var     array       Dirty words.
     */
    var array $dirty_words;

    /**
     * @access  private
     * @var     string      Separator.
     */
    var string $sep = '|';

    /**
     * @access  private
     * @var     string      Note.
     */
    var string $note = '#';

    /**
     * @access  private
     * @var     int         Level.
     * @note    0: all levers, other: the higher the value, the lower the lever.
     */
    var int $lev = 0;

    /**
     * @access  private
     * @var     string      Mark.
     */
    var string $mark = '$';


    /* {{{ function qp_dirty( $filename, $lev, $sep, $note, $mark ) */
    /**
     * Initialize.
     *
     * @param string $filename File name.
     * @param int $lev Level.
     * @param string $sep Separator.
     * @param string $note Note.
     * @param string $mark Mark.
     */
    private function __construct(string $filename = '', int $lev = 0, string $sep = '|', string $note = '#', string $mark = '$')
    {
        $this->file_name = $filename;
        $this->sep = $sep;
        $this->note = '#';
        $this->lev = $lev;
        $this->mark = $mark;
        if (!empty($filename)) {
            $this->read_dirty($filename);
        } else {
            return (-1);
        } // if
        return (0);
    }

    /* }}} */

    public function __destruct()
    {

    }

    public static function getInstance(): DirtyFilter
    {
        if (!self::$instance) {
            self::$instance = new self(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dirty.txt');
            self::$instance->read_dirty();
        }
        return self::$instance;
    }


    /* {{{ function set_file( $filename ) */
    /**
     * Set file.
     *
     * @param string $filename File name.
     */
    public function set_file(string $filename): int
    {
        $this->file_name = $filename;
        return (0);
    }
    /* }}} */


    /* {{{ function set_level( $lev ) */
    /**
     * Set level.
     *
     * @param int $lev Level.
     */
    public function set_level(int $lev = 0): int
    {
        $this->lev = $lev;
        return (0);
    }
    /* }}} */


    /* {{{ function set_sep( $sep ) */
    /**
     * Set separator.
     *
     * @param string $sep Separator.
     */
    public function set_sep(string $sep = '|'): int
    {
        $this->sep = $sep;
        return (0);
    }
    /* }}} */


    /* {{{ function set_note( $note ) */
    /**
     * Set note.
     *
     * @param string $note Note.
     */
    public function set_note(string $note = '#'): int
    {
        $this->note = $note;
        return (0);
    }
    /* }}} */


    /* {{{ function set_mark( $mark ) */
    /**
     * Set mark.
     *
     * @param string $mark Mark.
     */
    public function set_mark(string $mark = '$'): int
    {
        $this->mark = $mark;
        return (0);
    }
    /* }}} */


    /* {{{ function read_dirty( $filename ) */
    /**
     * Read dirty words from file.
     *
     * @return  int     0: ok, other: fail.
     */
    public function read_dirty($filename = ''): int
    {
        if (empty($filename)) {
            $filename = $this->file_name;
        } // if

        $lines = file($filename);
        if (empty($lines)) {
            return (-1);
        } // if

        $level = 1;
        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line)) {
                continue;
            } // if
            if ($this->note == $line[0]) {
                continue;
            } // if
            if ($this->mark == $line[0]) {
                $tmp = explode($this->mark, $line);
                $level = trim(@$tmp[1]);
                continue;
            } // if
            $word = explode($this->sep, $line);
            $this->dirty_words[trim($word[0])] = $level;
        } // foreach
        return (0);
    }
    /* }}} */


    /* {{{ function is_dirty( $word ) */
    /**
     * Check if a word is dirty.
     *
     * @param string $word Note.
     * @return  int     1: dirty, 0: not dirty.
     */
    public function is_dirty(string $word): int
    {
        if (!empty($this->dirty_words[$word])
            && (($this->dirty_words[$word] <= $this->lev)
                || 0 == $this->lev)) {
            return (1);
        } // if
        return (0);
    }
    /* }}} */


    /* {{{ function has_dirty( $str ) */
    /**
     * Check if a string has dirty words.
     *
     * @param string $str String.
     * @return  string  0: no dirty word, other: the dirty word found.
     */
    public function has_dirty(string $str)
    {
        reset($this->dirty_words);
        while (list($key, $val) = each($this->dirty_words)) {
            if (function_exists("iconv_strpos")) {
                $ret = @iconv_strpos($str, $key, 0, "UTF-8");
            } else {
                $ret = strpos($str, $key);
            } // if function_exists

            if ($ret !== false
                && (($val <= $this->lev) || 0 == $this->lev)) {
                return ($key);
            } // if
        } // while
        return (0);
    }
    /* }}} */

    /**
     * 替换脏字程序
     * 将匹配到的脏字替换为***字符串
     *
     * @param string $source 源字串
     * @param string $target 目标字串，使用引用传递值
     * @return int 0/errorno
     */
    public function replace_dirty(string $source, string &$target): int
    {
        $replace_str = '***';
        $target = $source;
        foreach ($this->dirty_words as $key => $value) {
            $target = str_replace($key, $replace_str, $target);
        }
        return 0;
    }
}